package sii.challenge.gestoreratings;

import sii.challenge.datastorage.DataStorage;

import sii.challenge.modello.Rating;

import sii.challenge.modello.SimilaritaUtenti;
import sii.challenge.modello.Utente;

/** Classe per la gestione dei ratings.
 * Tramite i dati presenti nel DataStorage e i gestori delle similarita implementa
 * l'algoritmo User-Item Based combined e produce la predizione del rating.
 * @author dario, francesco
 *
 */
public class GestoreRatings {

	/** Variabile per il data store. */
	private DataStorage data_storage;

	/* Gestore similarita utenti */
//	private GestoreSimilaritaUtenti gestore_similarita_utenti;

	/** Costruttore. 
	 * @throws Exception */
	public GestoreRatings() throws Exception {
		data_storage = DataStorage.getInstance();
//		gestore_similarita_utenti = new GestoreSimilaritaUtenti();

	}

	/** Restituisce il rating normalizzato */
	public Rating getRatingPredettoUserItemCombined(int idUtente, int idProfile) {
		int ratingValue=5;
		try {
			ratingValue = normalizzaRating(getRatingPredettoUserItemCombinedRaw(idUtente,idProfile));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return new Rating(idUtente,idProfile,ratingValue);
	}


	/** Restituisce il rating predetto, partendo dall'idUtente e idProfile
	 * usando l'algoritmo User-Item combined.
	 * @param idUtente l'id dell'utente votante.
	 * @param idProfile l'id dell'utente votato.
	 * @throws Exception 
	 *  */
	public int getRatingPredettoUserItemCombinedRaw(int idUtente, int idProfile) throws Exception {

		// variabile per l'utente.
		Utente utente_a = data_storage.getUtente(idUtente);

		// variabili di supporto per il calcolo del rating predetto. 
		int ratingPredettoRaw = 5;
		int somma_parziale_user_based = 0;
		int somma_similarita_user_based = 0;
		Rating r;
		
		Utente utenteB = data_storage.getMappaUtenti().get(idProfile);

//		double fattoreGender=0;
		// considerare la media che altri utenti hanno dato a idProfile e il gender

		if (utente_a != null) {
			ratingPredettoRaw = utente_a.getAvgRating();

			// calcola un rating predetto 
			for (SimilaritaUtenti sim_utenti: data_storage.readutentiSimili(utente_a)) {				
				Utente utenteSimile = data_storage.getUtente(sim_utenti.getUtente_b().getId());

				
				if((r=utenteSimile.getMappaRating().get(idProfile))!=null){

					somma_parziale_user_based += Math.round(sim_utenti.getSimilarita()*(r.getRatingValue() - utenteSimile.getAvgRating()));
					somma_similarita_user_based += Math.round(sim_utenti.getSimilarita());
					//					break;

				}
			}
			//			Utente utenteB;
			//			if((utenteB=data_storage.getMappaUtenti().get(idProfile))!=null)
			//				if(!utenteB.getGender().equals("U")){
			/*
					for(Rating r2:utente_a.getMappaRating().values()){
						String g=data_storage.getUtente(r2.getIdProfile()).getGender();
						if( g.equals("M")){
							genderM++;
							sommaVotiM+=r2.getRatingValue();
						}else if( g.equals("F")){
							genderF++;
							sommaVotiF+=r2.getRatingValue();
						}else
							continue;
					}

					if(sommaVotiM/genderM>sommaVotiF/genderF){
						if(utenteB.getGender().equals("M"))
							fattoreGender=1;
						else 
							fattoreGender=-1;
					}else if(sommaVotiM/genderM<sommaVotiF/genderF){
						if(utenteB.getGender().equals("M"))
							fattoreGender=-1;
						else
							fattoreGender=1;
					}
					if(utenteB.getGender().equals("M"))
						if(sommaVotiM!=0 && genderM!=0) 
							fattoreGender=sommaVotiM/genderM;
					if (utenteB.getGender().equals("F"))
						if(sommaVotiF!=0 && genderF!=0)
							fattoreGender=sommaVotiF/genderF;


			 */
			// TODO Metodo piu' intelligente di usare gender, ad es.?
			// fattoreGender = mediaVotiM/meidaVotiF   ???
			//					if (utente_a.getMediaVotiM() > utente_a.getMediaVotiF())
			//						if (utenteB.getGender().equals("M"))
			//							fattoreGender = 1.5;
			//						else if (utenteB.getGender().equals("F"))
			//							fattoreGender =-1.5;
			//					else if (utente_a.getMediaVotiM() < utente_a.getMediaVotiF())
			//						if (utenteB.getGender().equals("F"))
			//							fattoreGender = 1.5;
			//						else if (utenteB.getGender().equals("M"))
			//							fattoreGender = -1.5;
			//				}


			if (somma_similarita_user_based != 0 /*&& somma_similarita_item_based != 0*/) {
				int ratPredettoUser = utente_a.getAvgRating() + (somma_parziale_user_based / somma_similarita_user_based);
				ratingPredettoRaw = ratPredettoUser;
				//				if(fattoreGender!=0)
				//					ratingPredettoRaw=(int) Math.round(ratingPredettoRaw*fattoreGender);

			}else{
				
				
				if(utenteB!=null)
					if(!utenteB.getGender().equals("U")){
						System.out.println("nessun simile,ma uso le medie voti");
						if (utente_a.getMediaVotiM() > utente_a.getMediaVotiF()){
							if (utenteB.getGender().equals("M"))
								ratingPredettoRaw=(int) ((utente_a.getMediaVotiM()+utente_a.getAvgRating())/2);
						}else if (utente_a.getMediaVotiM() < utente_a.getMediaVotiF()){
							if (utenteB.getGender().equals("F"))
								ratingPredettoRaw=(int) ((utente_a.getMediaVotiF()+utente_a.getAvgRating())/2);
						}
												
					}else{
						System.out.println("non so niente");
						// TODO Usare utente_a.getAvgRating()
//						ratingPredettoRaw=utente_a.getAvgRating();
						ratingPredettoRaw = (int) utenteB.getMediaVotiRicevuti();
						
						
						
//						ratingPredettoRaw = (int) Math.round( (ratingPredettoRaw +
//															gestore_similarita_utenti.sim(utente_a, data_storage.getUtente(idProfile)).getSimilarita() *2.0));
					}
			}



		} 
		return (int) ((utenteB.getMediaVotiRicevuti() + ratingPredettoRaw)/2) ;
	}

	/** Normalizza un rating in un valore standard.
	 * @param ratingNonNormalizzato il valore di rating non normalizzato*/
	public int normalizzaRating(int ratingNonNormalizzato) {
		int ratingNormalizzato = Math.round(ratingNonNormalizzato);
		if (ratingNormalizzato <= 0.0) {
			ratingNormalizzato = 1;
		}
		if(ratingNormalizzato >= 10) {
			ratingNormalizzato = 10;
		}
		return ratingNormalizzato;
	}	
}
